#include "i2c.h"
#include "delay.h"

/*
    WM8960使用的I2C通信
*/


#define i2c_delay() delay_us(2)


void i2c_init(void)
{
    GPIO_InitTypeDef GPIO_Initstruct;

    RCC_AHB1PeriphClockCmd(I2C_CLK,ENABLE);

    GPIO_Initstruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Initstruct.GPIO_OType = GPIO_OType_OD;
    GPIO_Initstruct.GPIO_Pin = I2C_SDA | I2C_SCL;
    GPIO_Initstruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_PORT,&GPIO_Initstruct);

    // 设置总线空闲
    i2c_stop();
}


// 起始信号
void i2c_start(void)
{
    SDA_RELEASE();
    i2c_delay();
    SCL_RELEASE();
    i2c_delay();
    SDA_LOCK();
    i2c_delay();
    SCL_LOCK();
    i2c_delay();
}

// 结束信号
void i2c_stop(void)
{
    SCL_LOCK();
    SDA_LOCK();
    i2c_delay();
    SCL_RELEASE();
    i2c_delay();
    SDA_RELEASE();
}


// 发送应答
void i2c_send_ack(void)
{
    SCL_LOCK();
    i2c_delay();
    SDA(I2C_ACK);
    i2c_delay();
    SCL_RELEASE();
    i2c_delay();
    // 释放总线
    SCL_LOCK();
    SDA_RELEASE();
}

// 发送非应答
void i2c_send_nack(void)
{
    SCL_LOCK();
    i2c_delay();
    SDA(I2C_NACK);
    i2c_delay();
    SCL_RELEASE();
    i2c_delay();
    // 释放总线
    SCL_LOCK();
    SDA_RELEASE();
}


// 等待应答
uint8_t i2c_wait_ack(void)
{   
    uint8_t ret;
    // 释放总线
    SCL_LOCK();
    i2c_delay();
    SDA_RELEASE();
    i2c_delay();
    SCL_RELEASE();
    i2c_delay();
    if(READ_SDA)
        ret = I2C_NACK;
    else
        ret = I2C_ACK;
    // 钳住总线
    SCL_LOCK();
    SDA_RELEASE();
    return ret;
}

// 发送一个字节数据
void i2c_send_byte(uint8_t byte)
{
    uint8_t temp;
    for(temp = 0x80; temp !=0; temp>>=1)
    {
        SDA(temp & byte);
        i2c_delay();
        SCL_RELEASE();
        i2c_delay();
        SCL_LOCK();
        i2c_delay();
    }       
    // 释放总线
    SCL_LOCK();
    SDA_RELEASE();
}

// 接收一个字节数据
uint8_t i2c_recv_byte(void)
{
    uint8_t byte = 0x00;
    for(uint8_t i = 0; i < 9; i++)
    {
        SDA_RELEASE();
        i2c_delay();
        SCL_RELEASE();
        byte <<= 1;
        i2c_delay();
        if(READ_SDA) byte++;
        // 释放总线
        SCL_LOCK();
        i2c_delay();
    }
    return byte;
}


// i2c发送多字节数据
// 写入成功返回写入成功的个数，失败返回-1
int i2c_send_mutlibyte(uint8_t dev_addr,uint8_t *buff,uint8_t size)
{   
    uint8_t i;
    int ret = 0;
    // 起始信号
    i2c_start();
    // 发送写地址
    i2c_send_byte(dev_addr);
    if(I2C_ACK != i2c_wait_ack()) {ret = -1; goto out;}
    // 发送数据
    for(i = 0; i < size; i++)
    {
        i2c_send_byte(buff[i]);
        // 等待应答
        if(I2C_ACK == i2c_wait_ack()){ret++;}
        else {ret = -1; break;}
    }
    out:
    // 停止信号
    i2c_stop();
    return ret;
}

